package com.yangmf.auto_message_handle.Bot;

import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.mikuac.shiro.core.Bot;
import com.mikuac.shiro.core.BotPlugin;
import com.mikuac.shiro.dto.action.common.ActionData;
import com.mikuac.shiro.dto.action.response.GetForwardMsgResp;
import com.mikuac.shiro.dto.action.response.GroupFilesResp;
import com.mikuac.shiro.dto.action.response.MsgResp;
import com.mikuac.shiro.dto.action.response.UrlResp;
import com.mikuac.shiro.dto.event.message.GroupMessageEvent;
import com.mikuac.shiro.dto.event.notice.GroupUploadNoticeEvent;
import com.yangmf.auto_message_handle.constant.Message_Type;
import com.yangmf.auto_message_handle.constant.Other_constant;
import com.yangmf.auto_message_handle.constant.RedisConstant;
import com.yangmf.auto_message_handle.pojo.entity.DataBlocking;
import com.yangmf.auto_message_handle.pojo.entity.DataManager;
import com.yangmf.auto_message_handle.properties.AliOssProperties;
import com.yangmf.auto_message_handle.service.EventService;
import com.yangmf.auto_message_handle.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class Auto_handle_Bot extends BotPlugin {

    private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();


    @Autowired
    private DownLoadUtil downLoadUtil;

    @Autowired
    private Deskutil deskutil;

    @Autowired
    private DataManager dataManager;
    @Autowired
    private AliOssUtil aliOssUtil;
    @Autowired
    private AliOssProperties aliOssProperties;

    @Autowired
    private ImageAnalysisUtil imageAnalysisUtil;

    @Autowired
    private DataBlocking dataBlocking;

    @Autowired
    private EventService eventService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private DocumentParserUtil documentParserUtil;


    @Override
    public int onGroupMessage(Bot bot, GroupMessageEvent event) {
        //先处理转义字符
        String message = downLoadUtil.decodeUrl(event.getMessage());

        //获取消息编号
        Integer messageId = event.getMessageId();

        //随机睡眠0.5秒


/**
 * 1.文件上传事件开头为[CQ:file在这里忽略，在第三个中处理
 * 2.图片类型开头为 [CQ:image
 * 3.文本类消息无开头
 * 4.转发类消息开头为[CQ:forward
 * 5.[CQ:json为腾讯文档开头
 *
 * --记得加锁防止数据冲突
 */
        try {
            //处理消息
            executor.schedule(() -> {
                try {
                    handle_message(message, event, bot, messageId);
                } catch (IOException | NoApiKeyException | UploadFileException e) {
                    throw new RuntimeException(e);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }, 2000, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }


        return BotPlugin.MESSAGE_IGNORE;
    }

    @Override
    public int onGroupUploadNotice(Bot bot, GroupUploadNoticeEvent event) {

        /**
         * TODO:用file_id加入可以吗?不行
         */

        String fileId = event.getFile().getId();
        String fileName = event.getFile().getName();
        String fileName_up;
        log.info("filename{}", fileName);
        //获取file后缀如.docx
        String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
        byte[] fileData;

        if (fileId == null || fileName == null) {
            return MESSAGE_IGNORE;
        }
        //1.下载文件
        //获取下载链接
        UrlResp data = bot.getGroupFileUrl(event.getGroupId(), fileId, Other_constant.FILE_IGORE_ID).getData();
        try {
            fileData = downLoadUtil.downloadFileFromUrl(data.getUrl());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        try {
            String response = deskutil.getResponse("帮我判断一下下面这个文件名称是不是可以在文件名里知道包含的信息，如果不行则返回false，可以则返回true,只要返回true或者false这两种，不要给我你的分析过程，文件名:" + fileName);

            if (response.trim().replaceAll("^\"|\"$", "").equals("false")) {
                log.info("文件名称不能构成事件");
                String s = documentParserUtil.parseDocument(fileData, fileName);
                fileName = deskutil.getResponse("帮我获取下面这一段消息的标题，只返回标题不需要返回其他内容,你的分析过程不要给我,消息:" + s);


            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        try {
            fileName = deskutil.getResponse("消息为:" + fileName + ",帮我获取这段消息的核心标题信息并只返回核心信息给我，我要做成hashmap的一个key尽量简便又能区分，如果里面包含多个内容不用列举出来，如果有教学如何领取或者如何操作的也不用列举，只需要返回key给我，不需要格式，只要key的内容，如果无法获取出来请直接返回这段话，你的分析过程一定不要返回给我");
            fileName_up = fileName + fileSuffix;
            log.info("核心标题信息为:" + fileName);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        //2.上传文件
        //3.返回存储链接
        String fileUrl = aliOssUtil.upload(fileData, fileName_up);
        log.info("文件上传到:{}", fileUrl);
        String key;
        //判断在某个事件里面
        try {
            key = dataManager.Inmap(fileName);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        if (key == null) {
            try {
                dataManager.addData(fileName, fileUrl, Message_Type.FILE_MESSAGE, Other_constant.FILE_IGORE_ID);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        } else {
            try {
                dataManager.addData(key, fileUrl, Message_Type.FILE_MESSAGE, Other_constant.FILE_IGORE_ID);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }


        return MESSAGE_IGNORE;
    }


    public void handle_message(String message, GroupMessageEvent event, Bot bot, Integer messageId) throws IOException, NoApiKeyException, UploadFileException, InterruptedException {

        log.info("收到消息{},开始处理", message);


        if (message.equals("@全体成员"))
            return;
        //随机睡眠2秒


        /**
         *
         * TODO:
         * 还需要去除某些无用的消息
         */


        /**
         * 1.文件上传事件开头为[CQ:file在这里忽略，在第三个中处理
         * 2.图片类型开头为 [CQ:image
         * 3.文本类消息无开头
         * 4.转发类消息开头为[CQ:forward
         * 5.[CQ:json为腾讯文档开头
         *
         * --记得加锁防止数据冲突
         */
        int messageType = downLoadUtil.getMessageType(message);
        if (messageType == 1) {
            if (messageId != Other_constant.FOWARD_IGORE_ID)
                return;

            String response2 = deskutil.getResponse("帮我获取下面这一个文件消息的file_id，只返回file_id不需要返回其他内容，你的分析过程千万不要返回给我，消息为" + message);
            String fileId = response2.trim().replaceAll("^\"|\"$", "");
            log.info("file_id为:{}", fileId);

            ActionData<UrlResp> groupFileUrl = bot.getGroupFileUrl(event.getGroupId(), fileId, 1);

            byte[] fileData = downLoadUtil.downloadFileFromUrl(groupFileUrl.getData().getUrl());


            String response = deskutil.getResponse("帮我获取下面这一个文件消息的文件名称，只返回名称不需要返回其他内容，你的分析过程千万不要返回给我，文件后缀不要去掉，消息为" + message);
            String fileName = response.trim().replaceAll("^\"|\"$", "");


            //判断是不是转发的文件消息
            log.info("是转发文件。开始处理");
            //获取文件后缀
            String fileSuffix = fileName.substring(fileName.lastIndexOf("."));


            String response11 = deskutil.getResponse("帮我判断一下下面这个文件名称是不是可以在文件名里知道包含的信息，如果不行则返回false，可以则返回true,只要返回true或者false这两种，不要给我你的分析过程,名称:" + fileName);

            if (response11.trim().replaceAll("^\"|\"$", "").equals("false")) {
                log.info("文件名称不能构成事件");
                String s = documentParserUtil.parseDocument(fileData, fileName);
                fileName = deskutil.getResponse("帮我获取下面这一段消息的标题，只返回标题不需要返回其他内容,你的分析过程不要给我,消息:" + s);

            }


            fileName = deskutil.getResponse("消息为:" + fileName + ",帮我获取这段消息的核心标题信息并只返回核心信息给我，我要做成hashmap的一个key尽量简便又能区分，如果里面包含多个内容不用列举出来，如果有教学如何领取或者如何操作的也不用列举，只需要返回key给我，不需要格式，只要key的内容，如果无法获取出来请直接返回这段话，你的分析过程一定不要返回给我");
            String fileName_up = fileName + fileSuffix;


            String fileUrl = aliOssUtil.upload(fileData, fileName_up);
            log.info("文件上传成功，地址为:{}", fileUrl);
            String key;
            //判断在某个事件里面
            try {
                key = dataManager.Inmap(fileName);

            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            if (key == null) {
                try {
                    dataManager.addData(fileName, fileUrl, Message_Type.FILE_MESSAGE, Other_constant.FILE_IGORE_ID);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

            } else {
                try {
                    dataManager.addData(key, fileUrl, Message_Type.FILE_MESSAGE, Other_constant.FILE_IGORE_ID);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

            }


        } else if (messageType == 2) {
            log.info("开始处理图片消息");
            String s2 = deskutil.getResponse("消息：" + message + "帮我获取上面消息里面的图片的url，只需要返回url不需要返回其他内容");
            String s = s2.trim().replaceAll("^\"|\"$", "");

            String fileName1 = deskutil.getResponse("消息：" + message + "请将图片名称返回给我，只需要返回图片名称,不要其他任何你分析的内容");
            String fileName = fileName1.trim().replaceAll("^\"|\"$", "");

            byte[] fileData;

            try {
                fileData = downLoadUtil.downloadImageFromUrl(s);

            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            String fileUrl = aliOssUtil.upload(fileData, fileName);
            log.info("图片存储链接为{}", fileUrl);

            /**
             *
             * TODO:提示词还需完善
             */
            //处理图像识别
            String s1 = imageAnalysisUtil.analyzeOnlineImage(fileUrl, "帮我获取这张图片的核心标题信息并只返回核心信息给我，我要做成hashmap的一个key尽量简编又能区分，如果里面包含多个内容不用列举出来，如果有教学如何操作的也不用列举，只需要返回key给我，不需要格式，只要key的内容，分析过程不用给我，不能获取内容则返回“false");

            log.info("图片核心标题信息为{}", s1);
            //判断是不是在某个事件里面
            String key = dataManager.Inmap(s1);
            if (key == null) {
                log.info("添加图片信息到阻塞队列");
                dataBlocking.addData(fileUrl, messageId);


            } else {
                log.info("添加图片信息到key:{}", key);
                dataManager.addData(key, fileUrl, Message_Type.IMAGE_MESSAGE, messageId);
            }


            /**
             *TODO:
             *
             * 创建时间最近的事件再选择加入该事件中
             * 上传到共享map
             */

        } else if (messageType == 3) {

            message = deskutil.getResponse("帮我去除下列消息中的关于[CQ:face的一整个qq编码的内容，其他内容原封不动的返回给我，除了去除后的消息，其他的不要多返回,你的分析过程千万不要返回给我，去除后的内容不要给我变更，消息内容:" + message);

            String res = deskutil.getResponse("消息为:" + message + ",帮我获取这段消息的核心标题信息并只返回核心信息给我，我要做成hashmap的一个key尽量简便又能区分，如果里面包含多个内容不用列举出来，如果有教学如何领取或者如何操作的也不用列举，只需要返回key给我，不需要格式，只要key的内容，如果无法获取出来请直接返回这段话，你的分析过程一定不要返回给我");
            String key = dataManager.Inmap(res);
            if (key == null) {


                String response = deskutil.getResponse("消息为" + message + "，判断这个消息是不是不能构成一个的事件的信息，内容里面若只包含例如：'大家记得及时完成'，'注意时间','学委记得转发'，'或者大家记得.....',‘请大家....’这一类的消息,则返回false五个字,否则返回true，注意:如果是一长串信息里面包含有这些词不用返回false,你的推导过程不要给我，只需要返回ture或false");
                String cleanedResponse = response.trim().replaceAll("^\"|\"$", "");
                if (cleanedResponse.equals("false")) {
                    log.info("无法构成一个事件,忽略");
                    return;
                }
                /**
                 * TODO:
                 * 可以再创建一个队列，将这些信息加入队列中，等待5分钟后寻找时间最近的
                 */


                dataManager.addData(res, message, Message_Type.TEXT_MESSAGE, messageId);
                /**
                 *
                 * 创建一个新的key，并加入到map中
                 * 还需要判断属不属于一个时间的内容，如果不属于则加入blockingqueue中等待5分钟后寻找时间最近的
                 */
            } else {
                dataManager.addData(key, message, Message_Type.TEXT_MESSAGE, messageId);

            }

        } else if (messageType == 4) {


            //获取消息内容
            ActionData<GetForwardMsgResp> forwardMsg = bot.getForwardMsg(messageId);
            List<MsgResp> messages = forwardMsg.getData().getMessages();
            for (MsgResp msg1 : messages) {
                /**
                 *
                 //                 * 处理每一个消息
                 //                 * "消息内容: " + msg1.getMessage()
                 * "消息时间: " + msg1.getTime()
                 */
                String message2 = msg1.getMessage();
                //先处理转义字符再传入每条消息分别获取
                String s = downLoadUtil.decodeUrl(message2);
                handle_message(s, event, bot, Other_constant.FOWARD_IGORE_ID);


            }
        } else if (messageType == 5) {


            if (downLoadUtil.isTencentDoc(message)) {
                String docUrl;
                String docTitle;

                try {


                    docUrl = deskutil.getResponse("帮我获取下面的消息里的腾讯文档的链接不要忽略掉定位信息，只返回链接其他的一点都不要返回,消息为：" + message);
                    docTitle = deskutil.getResponse("帮我获取下面的消息里的腾讯文档的核心标题信息，不是title这个key，只返回标题其他的一点都不要返回，消息为：" + message);


                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                ;
                String key = dataManager.Inmap(docTitle);
                if (key == null) {
                    /**
                     * TODO:docTitle还需完善
                     */
                    dataManager.addData(docTitle, docUrl, Message_Type.TENCENT_DOC_MESSAGE, messageId);

                } else {
                    dataManager.addData(key, docUrl, Message_Type.TENCENT_DOC_MESSAGE, messageId);
                }


            }
        } else if (messageType == 6) {
            //太好了回复只能回复文本！
            String reply_text = downLoadUtil.extractContentFromCQReply(message);
            String reply_id = downLoadUtil.extractIdFromCQReply(message);

            //获取三天内事件的uuid
            List<String> eventuuid = eventService.getEventuuid(LocalDateTime.now().minusDays(3));
            Boolean isMember = false;

            for (String uuid : eventuuid) {
                isMember = stringRedisTemplate.opsForSet().isMember((RedisConstant.EVENT_START + uuid), reply_id);
                if (isMember) {
                    //添加到set中
                    log.info("回复消息找到事件,添加到事件中");
                    stringRedisTemplate.opsForSet().add(RedisConstant.EVENT_START + uuid, reply_id);
                    eventService.addmessageToEvent(uuid, reply_text);
                    break;
                }
            }

            if (!isMember) {
                log.info("回复消息没有找到对应的事件,丢弃");
                return;
            }


        } else {
            log.info("其他类型");
        }


        /**
         * 判断key是否在map中,如果在则返回对应的key,否则返回null
         * @param key
         * @return
         */
    }
}
